#include "NetClient.h"

CNetClient::CNetClient( 
					   INetNotify* pNetNotify, 
					   CLogModule* pLogModule, 
					   boost::asio::io_service& io_service_,
					   NetIDGenerator& net_id_
					   )
					   : m_pNetNotify(pNetNotify)
					   , m_pLogModule(pLogModule)
					   , io_service(io_service_)
					   , m_ClientSocket(io_service_)
					   , m_NetIDGenerator(net_id_)
{
	m_pLogModule->WriteLog(LOG_DEBUG,"CNetClient construct.");
	m_ullClientID = m_NetIDGenerator.get_id();;
}

CNetClient::~CNetClient(void)
{
	m_pLogModule->WriteLog(LOG_DEBUG,"CNetClient destruct.");
}

void CNetClient::SetServerAddress( char* pServerAddr, unsigned short nPort )
{
	boost::asio::ip::tcp::resolver resolver(io_service);
	boost::asio::ip::tcp::resolver::query query(pServerAddr,
		boost::lexical_cast<std::string,unsigned short>(nPort));
	m_resolver = resolver.resolve(query);
}

unsigned __int64 CNetClient::GetClientID()
{
	return m_ullClientID;
}

void CNetClient::Connect( void )
{
	m_pLogModule->WriteLog(LOG_DEBUG,"entry CNetClient::Connect.");
	boost::asio::async_connect(m_ClientSocket,m_resolver,boost::bind(&CNetClient::handle_connect,this,boost::asio::placeholders::error));
	m_pLogModule->WriteLog(LOG_DEBUG,"exit CNetClient::Connect.");
}

void CNetClient::handle_connect( const boost::system::error_code& error )
{
	m_pLogModule->WriteLog(LOG_DEBUG,"entry CNetClient::handle_connect.");
	if (!error)
	{
		m_pNetNotify->OnConnect(m_ullClientID
			,m_ClientSocket.local_endpoint().address().to_string().c_str()
			,m_ClientSocket.local_endpoint().port());
		m_ClientSocket.async_read_some(boost::asio::buffer(buffer_),
			boost::bind(&CNetClient::handle_read,this,boost::asio::placeholders::error,boost::asio::placeholders::bytes_transferred));
	}
	else
	{
		m_pLogModule->WriteLog(LOG_ERROR,"handle_connect error! code = %d, message = %s", error.value(), error.message().c_str());
		m_pNetNotify->OnErrorOccurred(m_ullClientID, error.value(),error.message().c_str());
		Close();
	}
	m_pLogModule->WriteLog(LOG_DEBUG,"exit CNetClient::handle_connect.");
}

void CNetClient::handle_read(const boost::system::error_code& error,const size_t bytes_transferred)
{
	m_pLogModule->WriteLog(LOG_DEBUG,"entry CNetClient::handle_read.");
	if (!error)
	{
		m_pNetNotify->OnReceiveData(m_ullClientID, buffer_.c_array(), bytes_transferred);
		m_ClientSocket.async_read_some(boost::asio::buffer(buffer_),
			boost::bind(&CNetClient::handle_read,this,boost::asio::placeholders::error,boost::asio::placeholders::bytes_transferred));
	}
	else
	{
		m_pLogModule->WriteLog(LOG_ERROR,"handle_read error! code = %d, message = %s", error.value(), error.message().c_str());
		if (error.value() != boost::asio::error::eof)
			m_pNetNotify->OnErrorOccurred(m_ullClientID, error.value(),error.message().c_str());
		Close();
	}
	m_pLogModule->WriteLog(LOG_DEBUG,"exit CNetClient::handle_read.");
}

void CNetClient::Close( void )
{
	io_service.post(boost::bind(&CNetClient::handle_close,this)); 
}

void CNetClient::handle_close( void )
{
	if (!m_ClientSocket.is_open()) return;
	m_ClientSocket.close();
	m_pNetNotify->OnClose(m_ullClientID);
}

void CNetClient::SendData( const char* pData, unsigned int unDataLength )
{
	m_pLogModule->WriteLog(LOG_DEBUG,"entry CNetClient::SendData.");
	if (pData == NULL || unDataLength == 0) return;
	if (!m_ClientSocket.is_open()) return;
	boost::asio::async_write(m_ClientSocket,boost::asio::buffer(pData,unDataLength),
		boost::bind(&CNetClient::handle_write,this,boost::asio::placeholders::error,boost::asio::placeholders::bytes_transferred));
	m_pLogModule->WriteLog(LOG_DEBUG,"exit CNetClient::SendData.");
}

void CNetClient::handle_write(const boost::system::error_code& error,const size_t bytes_transferred)
{
	m_pLogModule->WriteLog(LOG_DEBUG,"entry CNetClient::handle_write.");
	if (!error)
	{
		m_pNetNotify->OnSendData(m_ullClientID, bytes_transferred);
	} 
	else
	{
		m_pLogModule->WriteLog(LOG_ERROR,"handle_write error! code = %d, message = %s", error.value(), error.message().c_str());
		if (error.value() != boost::asio::error::eof)
			m_pNetNotify->OnErrorOccurred(m_ullClientID, error.value(), error.message().c_str());
		Close();
	}
	m_pLogModule->WriteLog(LOG_DEBUG,"exit CNetClient::handle_write.");
}